본문으로 건너뛰기

useDeferredValue

🧑🏻‍💻 useDeferredValue


useDeferredValue 는 UI 일부의 업데이트를 지연시킬 수 있는 React 훅이다.

✅ useDeferredValue 문법

const deferredValue = useDeferredValue(value)
  • value는 지연시키려는 값으로, 어떤 타입이든 가질 수 있다.
  • 업데이트가 발생하면 React는 먼저 이전 값으로 리렌더링을 시도하고, 그 다음 백그라운드에서 다시 새 값으로 리렌더링을 시도한다.

🧑🏻‍💻 알고 가기


✅ useDeferredValue는 언제 사용 하는가?

  • lazy를 사용한 지연 로딩 컴포넌트 코드 작성 시
  • Relay 및 Next.js와 같은 Suspense 지원 프레임워크를 사용하여 데이터를 가져올 때
  • 새 콘텐츠가 로딩 되는 동안 오래된 콘텐츠 표시할 때 (한 단계 아래 캐싱)

✅ 주의 사항

  • useDeferredValue에 전달하는 값은 문자열 및 숫자와 같은 원시값이거나, 컴포넌트의 외부에서 생성된 객체여야 한다. 렌더링마다 참조 값이 달라지는 새 객체를 바로 useDeferredValue에 전달하면 불필요한 백그라운드 리렌더링이 발생할 수 있다.
  • useDeferredValue는 추가 네트워크 요청을 막지 않는다. 즉 이전 값을 사용하여 렌더링하고 있는 순간에 새 값을 받으면 백그라운드에서 새 값으로 다시 렌더링하도록 예약한다.
  • <Suspense>와 함께 사용 시, 새 값으로 인한 백그라운드 업데이트로 인해 UI가 일시 중단되면 사용자에게 폴백이 표시되지 않는다. 대신 데이터가 로드될 때까지 기존 UI가 표시된다.
  • 백그라운드 리렌더링 후 화면에 커밋될 때까지 Effect를 실행하지 않는다.

🧑🏻‍💻 활용 및 생각할 거리


✅ Input 값을 지연시키는 동작 단계와 유의 사항를 알아보자

import { Suspense, useState, useDeferredValue } from 'react';
import SearchResults from './SearchResults.js';

export default function App() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
// 사용자 입력값과 현재 화면의 값(이전 값)이 다를 때 흐리게 보여줌
const isStale = query !== deferredQuery;

return (
<>
<label>
Search form:
<input value={query} onChange={e => setQuery(e.target.value)} />
</label>
<Suspense fallback={<h2>Loading...</h2>}>
<div style={{
opacity: isStale ? 0.5 : 1,
transition: isStale ? 'opacity 0.2s 0.2s linear' : 'opacity 0s 0s linear'
}}>
<SearchResults query={deferredQuery} />
</div>
</Suspense>
</>
);
}

✏️ 동작 단계

  • 사용자가 input form에 "ab" 를 작성하였다.
  • React는 새로운 query("ab")가 아닌 이전 deferredQuery( "a")로 다시 렌더링한다.
  • React가 백그라운드에서 querydeferredQuery를 모두 "ab"로 ‘동일하게 업데이트한 상태로 리렌더링을 완료’하게 되면 이를 화면에 표시한다.

✏️ 유의 사항

  • 유의할 점은 각 키 입력마다 네트워크 요청이 여전히 존재한다는 점이다. 여기서 지연되는 것은 네트워크 요청 자체가 아니라 결과를 화면에 표시하는 것이다.
  • 만약 사용자의 입력으로 백그라운드 렌더링이 일시 중단되면, React는 입력에 대한 렌더링 예약을 한 후 기존 렌더링을 다시 시도한다.
  • 이때 사용자는 최신 값과 지연 값이 동일한 상태의 렌더링이 준비될 때까지 지연된 UI를 보게 된다.
  • 따라서 사용자가 계속 입력하더라도 각 키 입력에 대한 응답은 모두 캐시되고, 백스페이스를 누르면 이전 값을 다시 가져오지 않는다.

✅ 디바운스 및 쓰로틀과 어떤 점이 다를까?

✏️ 디바운스

  • 사용자가 타이핑을 멈출 때까지(예: 1초 동안) 기다렸다가 렌더링을 한다.

✏️ 쓰로틀

  • 일정한 시간 간격으로(예: 최대 1초에 한 번) 렌더링을 한다.

✏️ useDeferredValue

  • 사용자의 input 값의 속도에 맞게 렌더링을 한다.

  • 즉 디바운스나 쓰로틀과 달리 고정된 지연 시간을 고려할 필요가 없다.

  • 예를 들어 사용자의 기기가 빠른 경우, 지연된 리렌더링은 거의 즉시 발생하기 때문에 눈에 띄지 않는다. 반면 사용자의 기기가 느린 경우, 목록이 input 값이 완성되는 것에 맞춰 렌더링 할 수 있게 된다.

  • 하지만 디바운스 및 쓰로틀은 네트워크 요청을 더 적게 실행할 수 있다는 점에서 여전히 유용하다. 이처럼 디바운스나 쓰로틀은 경우에 따라 유용하지만, useDeferredValue는 React 자체와 깊게 통합되어 있고 사용자의 기기에 맞게 조정되기 때문에 렌더링을 최적화하는 데 더 적합하다.